// <copyright file="UriReference.cs" company="Alan Dean">
// The MIT License

// Copyright (c) 2008 Alan Dean

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// </copyright>
// <author>Alan Dean</author>
// <email>alan.dean@thoughtpad.net</email>

namespace Semantic.Rdf
{
    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Runtime.Serialization;
    using System.Security.Permissions;
    using System.Xml;

    /// <summary>
    /// Represents an RDF URI reference.
    /// <para>This class cannot be inherited.</para>
    /// </summary>
    /// 
    /// <remarks>
    /// A URI reference within an RDF graph (an RDF URI reference) is a Unicode string.
    /// </remarks>
    /// 
    /// <seealso href="http://www.w3.org/TR/rdf-concepts/#section-URI-Vocabulary">
    /// URI-based Vocabulary and Node Identification
    /// </seealso>
    [Serializable]
    public sealed class UriReference : IComparable, ISerializable, IUriReference
    {
        #region fields

        /// <summary>
        /// Stores the <see cref="T:Semantic.Rdf.UriReference.BlankNode()"/> data.
        /// </summary>
        private static readonly UriReference _empty = new UriReference(string.Empty, true);

        /// <summary>
        /// Stores the <see cref="T:Semantic.Rdf.UriReference"/> string data.
        /// </summary>
        private string _value;

        /// <summary>
        /// Stores the <see cref="T:Semantic.Rdf.UriReference"/> <see cref="T:System.Uri"/> data.
        /// </summary>
        private Uri _uri;
        
        #endregion

        #region public UriReference(string)
        /// <overloads>
        /// Overloaded.
        /// Initializes a new instance of the <see cref="T:Semantic.Rdf.UriReference"/> class.
        /// </overloads>
        /// 
        /// <summary>
        /// Initializes a new instance of the <see cref="T:Semantic.Rdf.UriReference"/> class
        /// with the specified URI.
        /// </summary>
        /// 
        /// <param name="value">
        /// A string that identifies the resource to be represented by
        /// the <see cref="T:Semantic.Rdf.UriReference"/> instance.
        /// </param>
        /// 
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="value"/> is a <see langword="null"/> reference.
        /// </exception>
        /// <exception cref="T:System.UriFormatException">
        /// <paramref name="value"/> is empty.<br/>-or-<br/>
        /// The scheme specified in <paramref name="value"/> is not correctly formed.
        /// See <see cref="M:Semantic.Rdf.UriReference.CheckSchemeName(System.String)"/>.<br/>-or-<br/>
        /// <paramref name="value"/> contains too many slashes.<br/>-or-<br/>
        /// The password specified in <paramref name="value"/> is not valid.<br/>-or-<br/>
        /// The host name specified in <paramref name="value"/> is not valid.<br/>-or-<br/>
        /// The file name specified in <paramref name="value"/> is not valid.<br/>-or-<br/>
        /// The user name specified in <paramref name="value"/> is not valid.<br/>-or-<br/>
        /// The host or authority name specified in <paramref name="value"/> cannot be terminated by backslashes.<br/>-or-<br/>
        /// The port number specified in <paramref name="value"/> is not valid or cannot be parsed.<br/>-or-<br/>
        /// The length of <paramref name="value"/> exceeds 65534 characters.<br/>-or-<br/>
        /// The length of the scheme specified in <paramref name="value"/> exceeds 1023 characters.<br/>-or-<br/>
        /// There is an invalid character sequence in <paramref name="value"/>.<br/>-or-<br/>
        /// The MS-DOS path specified in <paramref name="value"/> must start with c:\\.
        /// </exception>
        /// 
        /// <remarks>
        /// <para>
        /// This constructor creates a <see cref="T:Semantic.Rdf.UriReference"/> instance from a URI string.
        /// It parses the URI, puts it in canonical format, and makes any required escape encodings.
        /// </para>
        /// <para>
        /// This constructor does not ensure that the <see cref="T:Semantic.Rdf.UriReference"/> refers to an accessible resource.
        /// </para>
        /// </remarks>
        /// 
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="value"/> is a <see langword="null"/> reference.
        /// </exception>
        public UriReference(string value)
            : this(new Uri(value, UriKind.Absolute))
        {
        }
        #endregion

        #region public UriReference(string, bool)
        /// <summary>
        /// Initializes a new instance of the <see cref="T:Semantic.Rdf.UriReference"/> class
        /// with the specified URI.
        /// </summary>
        /// 
        /// <param name="value">
        /// A string that identifies the resource to be represented by
        /// the <see cref="T:Semantic.Rdf.UriReference"/> instance.
        /// </param>
        /// <param name="blank">Indicates whether this is a blank node.</param>
        /// 
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="value"/> is a <see langword="null"/> reference.
        /// </exception>
        /// <exception cref="T:System.UriFormatException">
        /// <paramref name="value"/> is empty.<br/>-or-<br/>
        /// The scheme specified in <paramref name="value"/> is not correctly formed.
        /// See <see cref="M:Semantic.Rdf.UriReference.CheckSchemeName(System.String)"/>.<br/>-or-<br/>
        /// <paramref name="value"/> contains too many slashes.<br/>-or-<br/>
        /// The password specified in <paramref name="value"/> is not valid.<br/>-or-<br/>
        /// The host name specified in <paramref name="value"/> is not valid.<br/>-or-<br/>
        /// The file name specified in <paramref name="value"/> is not valid.<br/>-or-<br/>
        /// The user name specified in <paramref name="value"/> is not valid.<br/>-or-<br/>
        /// The host or authority name specified in <paramref name="value"/> cannot be terminated by backslashes.<br/>-or-<br/>
        /// The port number specified in <paramref name="value"/> is not valid or cannot be parsed.<br/>-or-<br/>
        /// The length of <paramref name="value"/> exceeds 65534 characters.<br/>-or-<br/>
        /// The length of the scheme specified in <paramref name="value"/> exceeds 1023 characters.<br/>-or-<br/>
        /// There is an invalid character sequence in <paramref name="value"/>.<br/>-or-<br/>
        /// The MS-DOS path specified in <paramref name="value"/> must start with c:\\.
        /// </exception>
        /// 
        /// <remarks>
        /// <para>
        /// This constructor creates a <see cref="T:Semantic.Rdf.UriReference"/> instance from a URI string.
        /// It parses the URI, puts it in canonical format, and makes any required escape encodings.
        /// </para>
        /// <para>
        /// This constructor does not ensure that the <see cref="T:Semantic.Rdf.UriReference"/> refers to an accessible resource.
        /// </para>
        /// </remarks>
        /// 
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="value"/> is a <see langword="null"/> reference.
        /// </exception>
        [SuppressMessage("Microsoft.Design", "CA1057:StringUriOverloadsCallSystemUriOverloads", Justification = "This is to allow correct handling of blank nodes which happen to be an absolute URI.")]
        public UriReference(string value, bool blank)
        {
            if (null == value)
            {
                throw new ArgumentNullException("value");
            }

            if (blank)
            {
                this._value = value;
            }
            else
            {
                this._uri = new Uri(value, UriKind.Absolute);
            }
        }
        #endregion

        #region public UriReference(Uri)
        /// <summary>
        /// Initializes a new instance of the <see cref="T:Semantic.Rdf.UriReference"/> class
        /// based on the specified URI.
        /// </summary>
        /// 
        /// <param name="uri">A <see cref="T:System.Uri"/> instance.</param>
        /// 
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="uri"/> is a <see langword="null"/> reference.
        /// </exception>
        /// 
        /// <remarks>
        /// This constructor does not ensure that the <see cref="T:Semantic.Rdf.UriReference"/> refers to an accessible resource.
        /// </remarks>
        /// 
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="uri"/> is a <see langword="null"/> reference.
        /// </exception>
        public UriReference(Uri uri)
        {
            if (null == uri)
            {
                throw new ArgumentNullException("uri");
            }

            if (uri.IsAbsoluteUri)
            {
                this._uri = uri;
            }
            else
            {
                this._value = uri.OriginalString;
            }
        }
        #endregion

        #region public UriReference(Uri, bool)
        /// <summary>
        /// Initializes a new instance of the <see cref="T:Semantic.Rdf.UriReference"/> class
        /// based on the specified URI.
        /// </summary>
        /// 
        /// <param name="uri">A <see cref="T:System.Uri"/> instance.</param>
        /// <param name="blank">Indicates whether this is a blank node.</param>
        /// 
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="uri"/> is a <see langword="null"/> reference.
        /// </exception>
        /// 
        /// <remarks>
        /// This constructor does not ensure that the <see cref="T:Semantic.Rdf.UriReference"/> refers to an accessible resource.
        /// </remarks>
        /// 
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="uri"/> is a <see langword="null"/> reference.
        /// </exception>
        public UriReference(Uri uri, bool blank)
        {
            if (null == uri)
            {
                throw new ArgumentNullException("uri");
            }

            if (blank)
            {
                this._value = uri.IsAbsoluteUri ? uri.AbsoluteUri : uri.OriginalString;
            }
            else
            {
                this._uri = new Uri(uri.IsAbsoluteUri ? uri.AbsoluteUri : uri.OriginalString, UriKind.Absolute);
            }
        }
        #endregion

        #region public UriReference(Uri, string)
        /// <summary>
        /// Initializes a new instance of the <see cref="T:Semantic.Rdf.UriReference"/> class
        /// based on the specified base URI and relative URI string.
        /// </summary>
        /// 
        /// <param name="baseUri">
        /// An absolute <see cref="T:System.Uri"/> that is the base for the
        /// new <see cref="T:Semantic.Rdf.UriReference"/> instance.
        /// </param>
        /// <param name="relativeUri">The relative URI to add to the base URI.</param>
        /// 
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="baseUri"/> is a <see langword="null"/> reference.
        /// </exception>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        /// <paramref name="baseUri"/> is a relative URI.
        /// </exception>
        /// <exception cref="T:System.UriFormatException">
        /// The scheme specified in <paramref name="relativeUri"/> is not correctly formed.<br/>-or-<br/>
        /// See <see cref="M:Semantic.Rdf.UriReference.CheckSchemeName(System.String)"/>.<br/>-or-<br/>
        /// <paramref name="relativeUri"/> contains too many slashes.<br/>-or-<br/>
        /// The password specified in <paramref name="relativeUri"/> is not valid.<br/>-or-<br/>
        /// The host name specified in <paramref name="relativeUri"/> is not valid.<br/>-or-<br/>
        /// The file name specified in <paramref name="relativeUri"/> is not valid.<br/>-or-<br/>
        /// The user name specified in <paramref name="relativeUri"/> is not valid.<br/>-or-<br/>
        /// The host or authority name specified in <paramref name="relativeUri"/> cannot be terminated by backslashes.<br/>-or-<br/>
        /// The port number specified in <paramref name="relativeUri"/> is not valid or cannot be parsed.<br/>-or-<br/>
        /// The length of <paramref name="relativeUri"/> exceeds 65534 characters.<br/>-or-<br/>
        /// The length of the scheme specified in <paramref name="relativeUri"/> exceeds 1023 characters.<br/>-or-<br/>
        /// There is an invalid character sequence in <paramref name="relativeUri"/>.<br/>-or-<br/>
        /// The MS-DOS path specified in <paramref name="baseUri"/> must start with c:\\.
        /// </exception>
        /// 
        /// <remarks>
        /// This constructor creates a <see cref="T:Semantic.Rdf.UriReference"/> instance
        /// by combining the <paramref name="baseUri"/> and the <paramref name="relativeUri"/>.
        /// If <paramref name="relativeUri"/> is an absolute URI (containing a scheme, host name, and optionally a port number),
        /// the <see cref="T:Semantic.Rdf.UriReference"/> instance is created using only <paramref name="relativeUri"/>.
        /// This constructor does not ensure that the <see cref="T:Semantic.Rdf.UriReference"/> refers to an accessible resource.
        /// </remarks>
        /// 
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="baseUri"/> is a <see langword="null"/> reference.
        /// </exception>
        [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "This design is due to the base type implementation.")]
        [SuppressMessage("Microsoft.Design", "CA1057:StringUriOverloadsCallSystemUriOverloads", Justification = "This design is due to the base type implementation.")]
        public UriReference(Uri baseUri, string relativeUri)
        {
            if (null == baseUri)
            {
                throw new ArgumentNullException("baseUri");
            }

            this._uri = new Uri(new Uri(baseUri, relativeUri).AbsoluteUri, UriKind.Absolute);
        }
        #endregion

        #region public UriReference(Uri, Uri)
        /// <summary>
        /// Initializes a new instance of the <see cref="T:Semantic.Rdf.UriReference"/> class
        /// based on the combination of a specified base <see cref="T:System.Uri"/> instance
        /// and a relative <see cref="T:System.Uri"/> instance.
        /// </summary>
        /// 
        /// <param name="baseUri">
        /// An absolute <see cref="T:System.Uri"/> that is the base for the
        /// new <see cref="T:Semantic.Rdf.UriReference"/> instance.
        /// </param>
        /// <param name="relativeUri">
        /// A relative <see cref="T:System.Uri"/> instance that is combined with <paramref name="baseUri"/>.
        /// </param>
        /// 
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="baseUri"/> is a <see langword="null"/> reference.
        /// </exception>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        /// <paramref name="baseUri"/> is a relative URI.
        /// </exception>
        /// <exception cref="T:System.NullReferenceException">
        /// <paramref name="relativeUri"/> is a <see langword="null"/> reference.
        /// </exception>
        /// <exception cref="T:System.UriFormatException">
        /// The URI formed by combining <paramref name="baseUri"/> and <paramref name="relativeUri"/> is empty or contains only spaces.<br/>-or-<br/>
        /// The scheme specified in the URI formed by combining <paramref name="baseUri"/> and <paramref name="relativeUri"/> is not valid.<br/>-or-<br/>
        /// The URI formed by combining <paramref name="baseUri"/> and <paramref name="relativeUri"/> contains too many slashes.<br/>-or-<br/>
        /// The password specified in the URI formed by combining <paramref name="baseUri"/> and <paramref name="relativeUri"/> is not valid.<br/>-or-<br/>
        /// The host name specified in the URI formed by combining <paramref name="baseUri"/> and <paramref name="relativeUri"/> is not valid.<br/>-or-<br/>
        /// The file name specified in the URI formed by combining <paramref name="baseUri"/> and <paramref name="relativeUri"/> is not valid.<br/>-or-<br/>
        /// The user name specified in the URI formed by combining <paramref name="baseUri"/> and <paramref name="relativeUri"/> is not valid.<br/>-or-<br/>
        /// The host or authority name specified in the URI formed by combining <paramref name="baseUri"/> and <paramref name="relativeUri"/> cannot be terminated by backslashes.<br/>-or-<br/>
        /// The port number specified in the URI formed by combining <paramref name="baseUri"/> and <paramref name="relativeUri"/> is not valid or cannot be parsed.<br/>-or-<br/>
        /// The length of the URI formed by combining <paramref name="baseUri"/> and <paramref name="relativeUri"/> exceeds 65534 characters.<br/>-or-<br/>
        /// The length of the scheme specified in the URI formed by combining <paramref name="baseUri"/> and <paramref name="relativeUri"/> exceeds 1023 characters.<br/>-or-<br/>
        /// There is an invalid character sequence in the URI formed by combining <paramref name="baseUri"/> and <paramref name="relativeUri"/>.<br/>-or-<br/>
        /// The MS-DOS path specified in <paramref name="baseUri"/> must start with c:\\.
        /// </exception>
        /// 
        /// <remarks>
        /// This constructor creates a <see cref="T:Semantic.Rdf.UriReference"/> instance
        /// by combining the <paramref name="baseUri"/> and the <paramref name="relativeUri"/>.
        /// If <paramref name="relativeUri"/> is an absolute URI (containing a scheme, host name, and optionally a port number),
        /// the <see cref="T:Semantic.Rdf.UriReference"/> instance is created using only <paramref name="relativeUri"/>.
        /// This constructor does not ensure that the <see cref="T:Semantic.Rdf.UriReference"/> refers to an accessible resource.
        /// </remarks>
        /// 
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="baseUri"/> is a <see langword="null"/> reference.<br/>-or-<br/>
        /// <paramref name="relativeUri"/> is a <see langword="null"/> reference.
        /// </exception>
        public UriReference(Uri baseUri, Uri relativeUri)
        {
            if (null == baseUri)
            {
                throw new ArgumentNullException("baseUri");
            }

            if (null == relativeUri)
            {
                throw new ArgumentNullException("relativeUri");
            }

            this._uri = new Uri(new Uri(baseUri, relativeUri).AbsoluteUri, UriKind.Absolute);
        }
        #endregion

        #region private UriReference(SerializationInfo, StreamingContext)
        /// <summary>
        /// Initializes a new instance of the <see cref="T:Semantic.Rdf.UriReference"/> class
        /// from the specified instances of the <see cref="T:System.Runtime.Serialization.SerializationInfo"/>
        /// and <see cref="T:System.Runtime.Serialization.StreamingContext"/> classes.
        /// </summary>
        /// 
        /// <param name="info">
        /// An instance of the  <see cref="T:System.Runtime.Serialization.SerializationInfo"/> class
        /// containing the information required to serialize the
        /// new <see cref="T:Semantic.Rdf.UriReference"/> instance. 
        /// </param>
        /// <param name="context">
        /// An instance of the <see cref="T:System.Runtime.Serialization.StreamingContext"/> class
        /// containing the source of the serialized stream associated with the
        /// new <see cref="T:Semantic.Rdf.UriReference"/> instance.
        /// </param>
        /// 
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="info"/> is a <see langword="null"/> reference.
        /// </exception>
        private UriReference(SerializationInfo info, StreamingContext context)
        {
            if (null == info)
            {
                throw new ArgumentNullException("info");
            }

            string uri = info.GetString("_uri");

            if (null == uri)
            {
                this._value = info.GetString("_value");
            }
            else
            {
                this._uri = new Uri(uri, UriKind.Absolute);
            }
        }
        #endregion

        #region public bool IsBlankNode
        /// <summary>
        /// Gets a value indicating whether this instance is a blank node.
        /// </summary>
        /// 
        /// <remarks>
        /// <para>
        /// The blank nodes in an RDF graph are drawn from an infinite set.
        /// This set of blank nodes, the set of all
        /// <see href="http://www.w3.org/TR/rdf-concepts/#dfn-URI-reference">RDF URI references</see>
        /// and the set of all <see href="http://www.w3.org/TR/rdf-concepts/#dfn-literal">literals</see> are pairwise disjoint.
        /// </para>
        /// <para>Otherwise, this set of blank nodes is arbitrary.</para>
        /// <para>
        /// RDF makes no reference to any internal structure of blank nodes.
        /// Given two blank nodes, it is possible to determine whether or not they are the same.
        /// </para>
        /// </remarks>
        /// 
        /// <seealso href="http://www.w3.org/TR/rdf-concepts/#section-blank-nodes">Blank Nodes</seealso>
        public bool IsBlankNode
        {
            get
            {
                return (null == this._uri);
            }
        }
        #endregion

        #region public string LexicalForm
        /// <summary>
        /// Gets the <see href="http://www.w3.org/TR/rdf-concepts/#dfn-URI-reference">URI reference</see> lexical form.
        /// </summary>
        /// 
        /// <value>
        /// A <see href="http://www.w3.org/TR/rdf-concepts/#ref-unicode">Unicode</see>
        /// <see langword="string"/> that:
        /// <list type="bullet">
        /// <item>does not contain any control characters ( #x00 - #x1F, #x7F-#x9F)</item>
        /// <item>
        /// and would produce a valid URI character sequence (per RFC2396 <see href="http://www.w3.org/TR/rdf-concepts/#ref-uris">URI</see>, sections 2.1)
        /// representing an absolute URI with optional fragment identifier when subjected to the encoding described below.
        /// </item>
        /// </list>
        /// </value>
        /// 
        /// <remarks>
        /// The encoding consists of:
        /// <list type="number">
        /// <item>
        /// encoding the Unicode string as UTF-8 <see href="http://www.w3.org/TR/rdf-concepts/#ref-rfc-2279">RFC-2279</see>, giving a sequence of octet values.
        /// </item>
        /// <item>%-escaping octets that do not correspond to permitted US-ASCII characters.</item>
        /// </list>
        /// <para>
        /// The disallowed octets that must be %-escaped include all those that do not correspond to US-ASCII characters,
        /// and the excluded characters listed in Section 2.4 of <see href="http://www.w3.org/TR/rdf-concepts/#ref-uris">URI</see>,
        /// except for the number sign (#), percent sign (%), and the square bracket characters re-allowed in
        /// <see href="http://www.w3.org/TR/rdf-concepts/#ref-rfc-2732">RFC-2732</see>.
        /// </para>
        /// <para>
        /// Disallowed octets must be escaped with the URI escaping mechanism
        /// (that is, converted to %HH, where HH is the 2-digit hexadecimal numeral corresponding to the octet value).
        /// </para>
        /// <para>
        /// Two RDF URI references are equal if and only if they compare as equal, character by character, as Unicode strings.
        /// </para>
        /// <para>
        /// <strong>Note:</strong>
        /// RDF URI references are compatible with the <see href="http://www.w3.org/TR/xmlschema-2/#anyURI">anyURI</see> datatype as defined by
        /// XML schema datatypes <see href="http://www.w3.org/TR/rdf-concepts/#ref-xml-schema2">XML-SCHEMA2</see>,
        /// constrained to be an absolute rather than a relative URI reference.
        /// </para>
        /// <para>
        /// <strong>Note:</strong>
        /// RDF URI references are compatible with
        /// <see href="http://www.w3.org/TR/2003/PR-xml-names11-20031105/#IRIs">International Resource Identifiers</see>
        /// as defined by <see href="http://www.w3.org/TR/rdf-concepts/#ref-xml-names11">XML Namespaces 1.1</see>.
        /// </para>
        /// <para>
        /// <strong>Note:</strong>
        /// this section anticipates an RFC on Internationalized Resource Identifiers.
        /// Implementations may issue warnings concerning the use of RDF URI References that do not conform with
        /// <see href="http://www.w3.org/TR/rdf-concepts/#ref-iri">IRI draft</see> or its successors.
        /// </para>
        /// <para>
        /// <strong>Note:</strong>
        /// The restriction to absolute URI references is found in this abstract syntax.
        /// When there is a well-defined base URI, concrete syntaxes, such as RDF/XML,
        /// may permit relative URIs as a shorthand for such absolute URI references.
        /// </para>
        /// <para>
        /// <strong>Note:</strong>
        /// Because of the risk of confusion between RDF URI references that would be equivalent if derefenced,
        /// the use of %-escaped characters in RDF URI references is strongly discouraged.
        /// See also the <see href="http://www.w3.org/2001/tag/issues.html#URIEquivalence-15">URI equivalence issue</see>
        /// of the Technical Architecture Group <see href="http://www.w3.org/TR/rdf-concepts/#ref-TAG">TAG</see>.
        /// </para>
        /// </remarks>
        public string LexicalForm
        {
            get
            {
                return (null != this._uri) ? this._uri.AbsoluteUri : this._value;
            }
        }
        #endregion

        #region public static UriReference BlankNode()
        /// <overloads>
        /// Overloaded.
        /// Returns a blank node.
        /// </overloads>
        /// 
        /// <summary>Returns an empty blank node.</summary>
        /// 
        /// <returns>A triple describing an empty blank node.</returns>
        /// 
        /// <seealso href="http://www.w3.org/2005/rules/wg/wiki/bNode_Semantics">bNode Semantics</seealso>
        /// <seealso href="http://msdn2.microsoft.com/en-us/library/aa303696.aspx">What is an RDF Blank Node?</seealso>
        public static UriReference BlankNode()
        {
            return _empty;
        }
        #endregion

        #region public static UriReference BlankNode(int)
        /// <summary>Returns an blank node with the specified value.</summary>
        /// 
        /// <param name="value">The value of the blank node.</param>
        /// 
        /// <returns>A triple describing a blank node.</returns>
        /// 
        /// <seealso href="http://www.w3.org/2005/rules/wg/wiki/bNode_Semantics">bNode Semantics</seealso>
        /// <seealso href="http://msdn2.microsoft.com/en-us/library/aa303696.aspx">What is an RDF Blank Node?</seealso>
        public static UriReference BlankNode(int value)
        {
            return BlankNode("_:" + XmlConvert.ToString(value));
        }
        #endregion

        #region public static UriReference BlankNode(Guid)
        /// <summary>Returns an blank node with the specified value.</summary>
        /// 
        /// <param name="value">The value of the blank node.</param>
        /// 
        /// <returns>A triple describing a blank node.</returns>
        /// 
        /// <seealso href="http://www.w3.org/2005/rules/wg/wiki/bNode_Semantics">bNode Semantics</seealso>
        /// <seealso href="http://msdn2.microsoft.com/en-us/library/aa303696.aspx">What is an RDF Blank Node?</seealso>
        public static UriReference BlankNode(Guid value)
        {
            return BlankNode("_:" + XmlConvert.ToString(value));
        }
        #endregion

        #region public static UriReference BlankNode(string)
        /// <summary>Returns an blank node with the specified value.</summary>
        /// 
        /// <param name="value">The value of the blank node.</param>
        /// 
        /// <returns>A triple describing a blank node.</returns>
        /// 
        /// <remarks>
        /// bNodes serve the purpose of representing resources which cannot be named at present.
        /// For example, bNodes allow us to represent something like "somebody whose name is 'John' and who is 25 years old".
        /// This can be represented using the following triples:
        /// <code>
        /// (_:X, name, "John")<br/>
        /// (_:X, age, "25"xsd:decimal)
        /// </code>
        /// In this particular notation, blank nodes always start with '<c>_:</c>', followed by a name to identify the blank node,
        /// so that the same blank node can be referenced in several triples of the same graph (a graph is a set of triples).
        /// </remarks>
        /// 
        /// <seealso href="http://www.w3.org/2005/rules/wg/wiki/bNode_Semantics">bNode Semantics</seealso>
        /// <seealso href="http://msdn2.microsoft.com/en-us/library/aa303696.aspx">What is an RDF Blank Node?</seealso>
        public static UriReference BlankNode(string value)
        {
            return new UriReference(value, true);
        }
        #endregion

        #region public static implicit operator string(UriReference)
        /// <summary>
        /// Implicitly converts an instance of the
        /// <see cref="T:Semantic.Rdf.UriReference"/> type
        /// to a <see langword="string"/>.
        /// </summary>
        /// 
        /// <param name="value">The instance to implicitly convert.</param>
        /// 
        /// <returns>A <see langword="string"/> representation.</returns>
        public static implicit operator string(UriReference value)
        {
            return (null == value) ? null as string : value.ToString();
        }
        #endregion

        #region public static implicit operator UriReference(string)
        /// <summary>
        /// Implicitly converts a <see langword="string"/>
        /// to an instance of the
        /// <see cref="T:Semantic.Rdf.UriReference"/> type.
        /// </summary>
        /// 
        /// <param name="value">The value to implicitly convert.</param>
        /// 
        /// <returns>
        /// An instance of the <see cref="T:Semantic.Rdf.UriReference"/> type.
        /// </returns>
        [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "This design is intentional.")]
        public static implicit operator UriReference(string value)
        {
            return (null == value) ? null as UriReference : new UriReference(value);
        }
        #endregion

        #region public static bool operator ==(UriReference, UriReference)
        /// <summary>Implements the equality operator for this type.</summary>
        /// 
        /// <param name="operand1">The first operand.</param>
        /// <param name="operand2">The second operand.</param>
        /// 
        /// <returns>
        /// Returns <see langword="true"/> if the values of the operands are equal;
        /// otherwise, <see langword="false"/>.
        /// </returns>
        /// 
        /// <remarks>The equality operator is strongly-typed.</remarks>
        public static bool operator ==(UriReference operand1, UriReference operand2)
        {
            return (0 == UriReference.Compare(operand1, operand2));
        }
        #endregion

        #region public static bool operator !=(UriReference, UriReference)
        /// <summary>Implements the inequality operator for this type.</summary>
        /// 
        /// <param name="operand1">The first operand.</param>
        /// <param name="operand2">The second operand.</param>
        /// 
        /// <returns>
        /// Returns <see langword="true"/> if the values of its operands are not equal;
        /// otherwise, <see langword="false"/>.
        /// </returns>
        /// 
        /// <remarks>The inequality operator is strongly-typed.</remarks>
        public static bool operator !=(UriReference operand1, UriReference operand2)
        {
            return (0 != UriReference.Compare(operand1, operand2));
        }
        #endregion

        #region public static bool operator <(UriReference, UriReference)
        /// <summary>Implements the less than operator for this type.</summary>
        /// 
        /// <param name="operand1">The first operand.</param>
        /// <param name="operand2">The second operand.</param>
        /// 
        /// <returns>
        /// Returns <see langword="true"/> if the first operand is less than the second operand;
        /// otherwise, <see langword="false"/>.
        /// </returns>
        /// 
        /// <remarks>The operator is strongly-typed.</remarks>
        public static bool operator <(UriReference operand1, UriReference operand2)
        {
            return (UriReference.Compare(operand1, operand2) < 0);
        }
        #endregion

        #region public static bool operator >(UriReference, UriReference)
        /// <summary>Implements the greater than operator for this type.</summary>
        /// 
        /// <param name="operand1">The first operand.</param>
        /// <param name="operand2">The second operand.</param>
        /// 
        /// <returns>
        /// Returns <see langword="true"/> if the first operands is greater than the second operand;
        /// otherwise, <see langword="false"/>.
        /// </returns>
        /// 
        /// <remarks>The operator is strongly-typed.</remarks>
        public static bool operator >(UriReference operand1, UriReference operand2)
        {
            return (UriReference.Compare(operand1, operand2) > 0);
        }

        #endregion

        #region public static int Compare(UriReference, UriReference)
        /// <summary>Compares two instances of this type.</summary>
        /// 
        /// <param name="comparand1">The first comparand.</param>
        /// <param name="comparand2">The second comparand.</param>
        /// 
        /// <returns>
        /// A 32-bit signed integer indicating the lexical relationship between the two comparands.
        /// <list type="table">
        /// <listheader>
        ///   <term>Value Type</term>
        ///   <description>Condition</description>
        /// </listheader>
        /// <item>
        ///   <term>Less than zero</term>
        ///   <description><paramref name="comparand1"/> is less than <paramref name="comparand2"/>.</description>
        /// </item>
        /// <item>
        ///   <term>Zero</term>
        ///   <description><paramref name="comparand1"/> equals <paramref name="comparand2"/>.</description>
        /// </item>
        /// <item>
        ///   <term>Greater than zero</term>
        ///   <description><paramref name="comparand1"/> is greater than <paramref name="comparand2"/>.</description>
        /// </item>
        /// </list>
        /// </returns>
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Only compare this type.")]
        public static int Compare(UriReference comparand1, UriReference comparand2)
        {
            return object.ReferenceEquals(comparand1, comparand2)
                ? 0
                : string.Compare(
                    object.ReferenceEquals(null, comparand1) ? null as string : comparand1.LexicalForm,
                    object.ReferenceEquals(null, comparand2) ? null as string : comparand2.LexicalForm,
                    StringComparison.OrdinalIgnoreCase);
        }
        #endregion

        #region public static IUriReference ValidateUriReference(IUriReference)
        /// <summary>Validates that the specified <paramref name="obj"/> is not a blank node.</summary>
        /// <param name="obj">The URI reference to be validated.</param>
        /// <returns>The validated <paramref name="obj"/>.</returns>
        public static IUriReference ValidateUriReference(IUriReference obj)
        {
            if (null == obj)
            {
                throw new ArgumentNullException("obj");
            }

            if (obj.IsBlankNode)
            {
                throw new ArgumentOutOfRangeException("obj");
            }

            return obj;
        }
        #endregion

        #region public override bool Equals(object)
        /// <summary>
        /// Determines if the specified <paramref name="obj"/> is equal to this instance..
        /// </summary>
        /// 
        /// <param name="obj">The <see langword="object"/> to compare with this instance.</param>
        /// 
        /// <returns>
        /// Returns <see langword="true"/> if the specified <paramref name="obj"/> is equal to this instance;
        /// otherwise <see langword="false"/>.
        /// </returns>
        public override bool Equals(object obj)
        {
            bool result = false;

            if (!object.ReferenceEquals(null, obj))
            {
                if (object.ReferenceEquals(this, obj))
                {
                    result = true;
                }
                else
                {
                    UriReference cast = (obj as UriReference);

                    if (!object.ReferenceEquals(null, cast))
                    {
                        result = (0 == UriReference.Compare(this, cast));
                    }
                }
            }

            return result;
        }
        #endregion

        #region public override int GetHashCode()
        /// <summary>Returns the hash code for this instance.</summary>
        /// <returns>A 32-bit signed integer hash code.</returns>
        public override int GetHashCode()
        {
            return this.ToString().GetHashCode();
        }
        #endregion

        #region public override string ToString()
        /// <summary>
        /// Returns a <see langword="string"/> representation of this instance.
        /// </summary>
        /// <returns>A <see langword="string"/> representation.</returns>
        public override string ToString()
        {
            return this.LexicalForm;
        }
        #endregion

        #region public int CompareTo(object)
        /// <summary>
        /// Compares the current instance with another <see langword="object"/> of the same type.
        /// </summary>
        /// 
        /// <param name="obj">An <see langword="object"/> to compare with this instance.</param>
        /// 
        /// <returns>
        /// A 32-bit signed integer that indicates the relative order of the objects being compared.
        /// The return value has these meanings:
        /// <list type="table">
        /// <listheader>
        ///   <term>Value Type</term>
        ///   <description>Meaning</description>
        /// </listheader>
        /// <item>
        ///   <term>Less than zero</term>
        ///   <description>This instance is less than <paramref name="obj"/>.</description>
        /// </item>
        /// <item>
        ///   <term>Zero</term>
        ///   <description>This instance is equal to <paramref name="obj"/>.</description>
        /// </item>
        /// <item>
        ///   <term>Greater than zero</term>
        ///   <description>This instance is greater than <paramref name="obj"/>.</description>
        /// </item>
        /// </list>
        /// </returns>
        /// 
        /// <exception cref="T:System.ArgumentException">
        /// <paramref name="obj"/> is not an instance of the
        /// <see cref="T:Semantic.Rdf.UriReference"/> type.
        /// </exception>
        public int CompareTo(object obj)
        {
            int comparison = 1;

            if (!object.ReferenceEquals(null, obj))
            {
                UriReference value = (obj as UriReference);

                if (object.ReferenceEquals(null, value))
                {
                    throw new ArgumentException(
                        string.Format(CultureInfo.InvariantCulture, Properties.Resources.ObjectMustBeOfTypeException_Message_Format, "UriReference"),
                        "obj");
                }

                comparison = UriReference.Compare(this, value);
            }

            return comparison;
        }
        #endregion

        #region void ISerializable.GetObjectData(SerializationInfo, StreamingContext)
        /// <summary>Returns the data needed to serialize the current instance.</summary>
        /// 
        /// <param name="info">
        /// A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> object containing the information
        /// required to serialize the <see cref="T:Semantic.Rdf.UriReference"/>.
        /// </param>
        /// <param name="context">
        /// A <see cref="T:System.Runtime.Serialization.StreamingContext"/> object containing the source and destination
        /// of the serialized stream associated with the <see cref="T:Semantic.Rdf.UriReference"/>.
        /// </param>
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (null == info)
            {
                throw new ArgumentNullException("info");
            }

            if (null == this._uri)
            {
                info.AddValue("_value", this._value);
            }
            else
            {
                info.AddValue("_uri", this._uri.AbsoluteUri);
            }
        }
        #endregion
    }
}